<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      class EventEmitter {
        constructor() {
          this.cache = {};
        }
        //订阅消息
        on(name, fn) {
          // 同时订阅多个消息，加入到数组中
          if (this.cache[name]) {
            this.cache[name].push(fn);
          } else {
            // 没有就创建一个数组回调函数
            this.cache[name] = [fn];
          }
        }
        // 取消订阅消息
        off(name, fn) {
          const tasks = this.cache[name];
          if (tasks) {
            const index = tasks.indexOf(f => f === fn);
            if (index >= 0) {
              tasks.splice(index, 1);
            }
          }
        }
        // 发布消息
        emit(name, param, once = false) {
          if (this.cache[name]) {
            // 创建副本，如果回调函数内继续注册相同事件，会造成死循环
            const tasks = this.cache[name].slice(); //浅拷贝
            // 依次执行消息中的回调函数
            for (let fn of tasks) {
              fn(param);
            }
            // 是否只订阅一次
            if (once) {
              delete this.cache[name];
            }
          }
        }
      }

      // 测试
      const eventBus = new EventEmitter();
      const task1 = (x) => {
        console.log("task1",x);
      };
      const task2 = () => {
        console.log("task2");
      };

      eventBus.on("task", task1);
      eventBus.on("task", task2);
      eventBus.off("task", task2);
      setTimeout(() => {
        eventBus.emit("task",'我给你的参数'); // task2
      }, 0);
    </script>
  </body>
</html>
